import pandas as pd
import numpy as np
from pandas import Series, DataFrame

### 三、pandas层次化索引
## 1 隐式构造
data0 = np.random.randint(0, 150, size=(6, 6))
index = [['一班', '一班', '一班', '二班', '二班', '二班'], ['张三', '李四', '王五', '赵六', '田七', '孙八']]
columns = [['期中', '期中', '期中', '期末', '期末', '期末'], ['语文', '数学', '英语', '语文', '数学', '英语']]
df = DataFrame(data=data0, index=index, columns=columns)
print(df)
print('-' * 7)
# Series也可以用相同方法创建多层索引
data1 = np.random.randint(0, 150, size=6)
s = Series(data=data1, index=index)
print(s)
print('-' * 7)

## 2 显式构造
# 2.1 使用arrays
data2 = np.random.randint(0, 150, size=(6, 6))
index = pd.MultiIndex.from_arrays([['一班', '一班', '一班', '二班', '二班', '二班'], ['张三', '李四', '王五', '赵六', '田七', '孙八']])
columns = pd.MultiIndex.from_arrays([['期中', '期中', '期中', '期末', '期末', '期末'], ['语文', '数学', '英语', '语文', '数学', '英语']])
df = DataFrame(data=data2, index=index, columns=columns)
print(df)
print('-' * 7)
# 2.2 使用tuples
data3 = np.random.randint(0, 150, size=(6, 6))
index = pd.MultiIndex.from_tuples([('一班', '张三'), ('一班', '李四'), ('一班', '王五'), ('二班', '赵六'), ('二班', '田七'), ('二班', '孙八')])
columns = pd.MultiIndex.from_arrays([['期中', '期中', '期中', '期末', '期末', '期末'], ['语文', '数学', '英语', '语文', '数学', '英语']])
df = DataFrame(data=data3, index=index, columns=columns)
print(df)
print('-' * 7)
# 2.3 使用product，优点：最简单，推荐使用；缺点：索引是个笛卡尔积的结果，不容易满足应用场景
data4 = np.random.randint(0, 150, size=(6, 6))
index = pd.MultiIndex.from_product([['一班', '二班'], ['张三', '李四', '王五']])
columns = pd.MultiIndex.from_product([['期中', '期末'], ['语文', '数学', '英语']])
df = DataFrame(data=data4, index=index, columns=columns)
print(df)
print('-' * 7)

## 3 多层索引对象的索引与切片操作
# 3.1 Series的操作
# 3.1.1 索引
print(s.loc['一班', '张三'])
print('-' * 7)
# 3.1.2 切片
print(s.loc['二班':])
print('-' * 7)
# 3.2 DataFrame的操作
# 3.2.1 行多级索引的索引和切片操作
# 索引
print(df.loc['一班', '张三'])
print('-' * 7)
# 切片
print(df.loc['一班': '一班'])
print('-' * 7)
# 3.2.2 列多级索引的索引和切片操作
# 索引
print(df['期中', '语文'])
print('-' * 7)
# 切片
print(df.loc[:, '期中': '期中'])
print('-' * 7)

## 4 索引的堆
print(df)
print('-' * 7)
print(df.stack(level=0).unstack())
print('-' * 7)

## 5 聚合操作
print(df.sum())
print('-' * 7)
# 先根据axis的值看对行还是对列进行操作，再去看level，level等于哪一层，哪一层就保留下来
print(df.sum(axis=0, level=0))  # 在将来版本这个方式将会被取消，使用以下操作
# print(df.groupby(axis=0, level=0).sum())
print('-' * 7)